package com.hyny.framework.platform.system.controller;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;

import com.hyny.framework.platform.system.annotation.Log;
import com.hyny.framework.platform.system.base.PageBean;
import com.hyny.framework.platform.system.entity.param.RoleAddUpdateParam;
import com.hyny.framework.platform.system.entity.param.RoleMenuFieldPowerParam;
import com.hyny.framework.platform.system.entity.param.RoleParam;
import com.hyny.framework.platform.system.entity.pojo.*;
import com.hyny.framework.platform.system.entity.vo.FieldPowerVO;
import com.hyny.framework.platform.system.entity.vo.MenuFieldPowerTreeVO;
import com.hyny.framework.platform.system.entity.vo.RoleListVO;
import com.hyny.framework.platform.system.entity.vo.RoleVO;
import com.hyny.framework.platform.system.enums.MenuOrFieldPowerTreeEnum;
import com.hyny.framework.platform.system.enums.MenuStatusEnum;
import com.hyny.framework.platform.system.enums.MenuTypeEnum;
import com.hyny.framework.platform.system.service.*;
import com.hyny.framework.platform.system.utils.bean.Result;
import com.hyny.framework.platform.system.utils.enums.FieldPowerTypeEnum;
import com.hyny.framework.base.enums.YesOrNoEnum;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 角色信息表(SysRole)表控制层
 *
 * @author 张崇阳
 * @since 2023-12-13 10:07:56
 */
@Api(tags = "角色管理")
@RestController
@ApiSupport(order = 3)
@RequestMapping("/sysRole")
@Slf4j
public class SysRoleController {
    /**
     * 服务对象
     */
    @Autowired
    private ILoginService iLoginService;
    @Autowired
    private SysRoleService sysRoleService;
    @Autowired
    private SysRoleMenuService sysRoleMenuService;
    @Autowired
    private SysMenuService sysMenuService;
    @Autowired
    private SysRoleFieldPowerService sysRoleFieldPowerService;
    @Autowired
    private SysFieldPowerService sysFieldPowerService;
    @Autowired
    private SysUserRoleService sysUserRoleService;


    @Log(value = "分页查询角色列表")
    @ApiOperation(value = "分页查询角色列表")
    @GetMapping("/page/{pageNum}/{pageSize}")
    @ApiOperationSupport(order = 1)
    public Result<PageBean<RoleListVO>> rolePage(@ApiParam(value = "页码", required = true)
                                             @PathVariable(value = "pageNum") Long pageNum,
                                                 @ApiParam(value = "页条数", required = true)
                                             @PathVariable(value = "pageSize") Long pageSize,
                                                 @ApiParam("查询参数") RoleParam param) {
        Page page = new Page(pageNum, pageSize);
        LambdaQueryWrapper<SysRole> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(StrUtil.isNotBlank(param.getId()), SysRole::getId, param.getId());
        lambdaQueryWrapper.like(StrUtil.isNotBlank(param.getRoleName()), SysRole::getRoleName, param.getRoleName());
        IPage<FieldPowerVO> iPage = sysRoleService.page(page, lambdaQueryWrapper);
        return Result.okPage(iPage);
    }


    @Log(value = "查询角色列表")
    @ApiOperation(value = "查询角色列表")
    @GetMapping("/list")
    @ApiOperationSupport(order = 2)
    public Result<List<RoleListVO>> roleList(@ApiParam("查询参数") RoleParam param) {
        LambdaQueryWrapper<SysRole> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(StrUtil.isNotBlank(param.getId()), SysRole::getId, param.getId());
        lambdaQueryWrapper.like(StrUtil.isNotBlank(param.getRoleName()), SysRole::getRoleName, param.getRoleName());
        return Result.ok(BeanUtil.copyToList(sysRoleService.list(lambdaQueryWrapper), RoleListVO.class));
    }

    @Log(value = "查询角色权限树")
    @ApiOperation(value = "查询角色权限树", notes = "获取无勾选的角色权限树,显示全量菜单和字段权限数据")
    @GetMapping("/menuFieldPowerTree")
    @ApiOperationSupport(order = 3)
    public Result<List<MenuFieldPowerTreeVO>> menuFieldPowerTree() {
        return Result.ok(menuFieldPowerTreeVOInfo(null));
//        return null;
    }


    @Log(value = "添加角色信息",persisted = true)
    @ApiOperation(value = "添加角色信息")
    @ApiOperationSupport(order = 4)
    @PostMapping("/add")
    public Result roleAdd(@RequestBody RoleAddUpdateParam param) {
        SysRole sysRole = new SysRole();
        sysRole.setRoleName(param.getRoleName());
        sysRoleService.save(sysRole);
        updateRoleCorrelation(sysRole.getId(), param);
        return Result.ok();
    }

    @Log(value = "获取角色信息")
    @ApiOperation(value = "获取角色信息", notes = "根据角色编码获取角色信息，")
    @GetMapping("/info/{id}")
    @ApiOperationSupport(order = 5)
    public Result<RoleVO> roleInfo(@ApiParam(value = "角色编码", required = true) @PathVariable("id") String id) {
        SysRole sysRole = sysRoleService.getById(id);
        RoleVO roleVO = BeanUtil.copyProperties(sysRole, RoleVO.class);
        roleVO.setMenuFieldPowerTreeVOS(menuFieldPowerTreeVOInfo(roleVO.getId()));

        return Result.ok(roleVO);
    }


    @Log(value = "修改角色信息",persisted = true)
    @ApiOperation(value = "修改角色信息")
    @ApiOperationSupport(order = 6)
    @PutMapping("/put/{id}")
    public Result roleUpdate(@ApiParam(value = "角色编码", required = true) @PathVariable("id") String id, @RequestBody RoleAddUpdateParam param) {
        LambdaUpdateWrapper<SysRole> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.set(SysRole::getRoleName, param.getRoleName());
        lambdaUpdateWrapper.eq(SysRole::getId, id);
        sysRoleService.update(lambdaUpdateWrapper);
        updateRoleCorrelation(Long.valueOf(id), param);
        return Result.ok();
    }


    @Log(value = "删除角色信息",persisted = true)
    @ApiOperation(value = "删除角色信息")
    @ApiOperationSupport(order = 7)
    @DeleteMapping("/delete/{id}")
    public Result roleDelete(@ApiParam(value = "角色编码", required = true) @PathVariable("id") String id) {
        sysRoleService.removeById(id);
        sysUserRoleService.remove(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId,id));
        sysRoleMenuService.remove(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, id));
        sysRoleFieldPowerService.remove(new LambdaQueryWrapper<SysRoleFieldPower>().eq(SysRoleFieldPower::getRoleId, id));
        iLoginService.logoutMenu(Long.valueOf(id));
        return Result.ok();
    }

    /**
     * 变更角色对应的权限信息
     * @param roleId
     * @param param
     */
    public void updateRoleCorrelation(Long roleId, RoleAddUpdateParam param) {
        List<SysRoleFieldPower> sysRoleFieldPowers = new ArrayList<>();
        List<SysRoleMenu> sysRoleMenus = new ArrayList<>();
        if(param.getRoleMenuFieldPowerParams()!=null){
            for (RoleMenuFieldPowerParam menuFieldPower : param.getRoleMenuFieldPowerParams()
            ) {
                if (menuFieldPower.getTreeType().equals(MenuOrFieldPowerTreeEnum.MENU)) {
                    sysRoleMenus.add(new SysRoleMenu(roleId, Long.valueOf(menuFieldPower.getId())));
                } else  if(menuFieldPower.getTreeType().equals(MenuOrFieldPowerTreeEnum.FIELD_POWER)) {
                    sysRoleFieldPowers.add(new SysRoleFieldPower(roleId, Long.valueOf(menuFieldPower.getId())));
                }
            }
        }

        sysRoleMenuService.remove(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
        sysRoleFieldPowerService.remove(new LambdaQueryWrapper<SysRoleFieldPower>().eq(SysRoleFieldPower::getRoleId, roleId));
        sysRoleMenuService.saveBatch(sysRoleMenus);
        sysRoleFieldPowerService.saveBatch(sysRoleFieldPowers);
        iLoginService.logoutMenu(roleId);
    }

//
    /***
     * 组装菜单树状结构
     * @param roleId 角色id 如果不为空，返回的树状角色有isSelected字段
     * @return
     */
    public List<MenuFieldPowerTreeVO> menuFieldPowerTreeVOInfo(String roleId) {
        LambdaQueryWrapper<SysMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.orderByAsc(SysMenu::getSort);
        lambdaQueryWrapper.orderByAsc(SysMenu::getCreatedTime);
        lambdaQueryWrapper.eq(SysMenu::getStatus, MenuStatusEnum.AVAILABLE);
        lambdaQueryWrapper.eq(SysMenu::getVisible, YesOrNoEnum.NO);
        //查询全量菜单信息
        List<SysMenu> menus = sysMenuService.list(lambdaQueryWrapper);
        //遍历出菜单的目录类型
        List<SysMenu> directoryMenus=menus.stream().filter(menu-> menu.getMenuType()== MenuTypeEnum.DIRECTORY).collect(Collectors.toList());
        //菜单目录类型po转VO
        List<MenuFieldPowerTreeVO> directoryMenuTree = BeanUtil.copyToList(directoryMenus, MenuFieldPowerTreeVO.class);

        //查询方法和字段全量的字段权限信息
        List<SysFieldPower> fieldPowerList = sysFieldPowerService.list(new LambdaQueryWrapper<SysFieldPower>().in(SysFieldPower::getType, FieldPowerTypeEnum.METHOD, FieldPowerTypeEnum.FIELD));
        //遍历出方法信息
        List<SysFieldPower> fieldPowerMethods = fieldPowerList.stream().filter(fp -> fp.getType() == FieldPowerTypeEnum.METHOD).collect(Collectors.toList());
        //字段权限，方法对应的字段集合key:方法id，value：字段
        Map<Long, List<SysFieldPower>> methodFieldPowerMaps = new HashMap<>();
        //遍历方法信息，将该方法下字段塞入map中
        for (SysFieldPower sysFieldPower : fieldPowerMethods
        ) {
            List<SysFieldPower> fieldPowerFields = fieldPowerList.stream().filter(fp -> fp.getType() == FieldPowerTypeEnum.FIELD && fp.getParentId().longValue() == sysFieldPower.getId().longValue()).collect(Collectors.toList());
            methodFieldPowerMaps.put(sysFieldPower.getId(), fieldPowerFields);
        }


        Map<Long, Long> roleFieldPowerMap = new HashMap<>();
        Map<Long, Long> roleMenuMap = new HashMap<>();

        //判断是否有角色信息，如果有查询角色拥有的菜单和字段权限
        if (StrUtil.isNotBlank(roleId)) {
            List<SysRoleFieldPower> sysRoleFieldPowers = sysRoleFieldPowerService.list(new LambdaQueryWrapper<SysRoleFieldPower>().eq(SysRoleFieldPower::getRoleId, roleId));
            List<SysRoleMenu> sysRoleMenus = sysRoleMenuService.list(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
            roleFieldPowerMap = sysRoleFieldPowers.stream().collect(Collectors.toMap(SysRoleFieldPower::getFieldPowerId, SysRoleFieldPower::getRoleId));
            roleMenuMap = sysRoleMenus.stream().collect(Collectors.toMap(SysRoleMenu::getMenuId, SysRoleMenu::getRoleId));
        }


        for (MenuFieldPowerTreeVO treeVO : directoryMenuTree
        ) {
            treeVO.setIsSelected(roleMenuMap.containsKey(Long.valueOf(treeVO.getId())) ? YesOrNoEnum.YES : YesOrNoEnum.NO);
            treeVO.setTreeType(MenuOrFieldPowerTreeEnum.MENU);
            treeVO.setChildMenuFieldPowerTrees(infoMenu(treeVO, menus, methodFieldPowerMaps, roleFieldPowerMap, roleMenuMap));

        }
        return directoryMenuTree;
    }

//
    /**
     * 组装二级菜单信息
     * @param menuFieldPowerTreeVO 当前父节点【一级目录】
     * @param menus                全量菜单信息
     * @param longListMap          字段权限信息
     * @param roleFieldPowerMap    选中的字段权限
     * @param roleMenuMap          选中的菜单
     * @return
     */
    public List<MenuFieldPowerTreeVO> infoMenu(MenuFieldPowerTreeVO menuFieldPowerTreeVO, List<SysMenu> menus, Map<Long, List<SysFieldPower>> longListMap, Map<Long, Long> roleFieldPowerMap, Map<Long, Long> roleMenuMap){
        List<SysMenu> menuList  = menus.stream().filter(menu -> menu.getMenuType() == MenuTypeEnum.MENU && String.valueOf(menu.getParentId()).equals(menuFieldPowerTreeVO.getId())).collect(Collectors.toList());
        if (menuList != null && menuList.size() > 0) {
            List<MenuFieldPowerTreeVO> menuListVOS = BeanUtil.copyToList(menuList, MenuFieldPowerTreeVO.class);
            for (MenuFieldPowerTreeVO menuTreeVO:menuListVOS){
                menuTreeVO.setIsSelected(roleMenuMap.containsKey(Long.valueOf(menuTreeVO.getId())) ? YesOrNoEnum.YES : YesOrNoEnum.NO);
                menuTreeVO.setTreeType(MenuOrFieldPowerTreeEnum.MENU);
                menuTreeVO.setChildMenuFieldPowerTrees(infoButton(menuTreeVO, menus,roleMenuMap));
                if(menuTreeVO.getChildMenuFieldPowerTrees()!=null){
                    menuTreeVO.getChildMenuFieldPowerTrees().addAll(infoFieldPower(menuTreeVO.getFieldPowerId(),longListMap, roleFieldPowerMap));
                }else{
                    menuTreeVO.setChildMenuFieldPowerTrees(infoFieldPower(menuTreeVO.getFieldPowerId(),longListMap, roleFieldPowerMap));
                }


            }
            return menuListVOS;
        }

        return null;
    }
//
    /**
     * 组装二级菜单的按钮权限信息
     * @param menuFieldPowerTreeVO 当前父节点【二级菜单】
     * @param menus                全量菜单信息
     * @param roleMenuMap          选中的菜单
     * @return
     */
    public List<MenuFieldPowerTreeVO> infoButton(MenuFieldPowerTreeVO menuFieldPowerTreeVO, List<SysMenu> menus, Map<Long, Long> roleMenuMap){
        List<SysMenu> buttonList  = menus.stream().filter(menu -> menu.getMenuType() == MenuTypeEnum.BUTTON && String.valueOf(menu.getParentId()).equals(menuFieldPowerTreeVO.getId())).collect(Collectors.toList());
        if (buttonList != null && buttonList.size() > 0) {
            List<MenuFieldPowerTreeVO> buttonListVOS = BeanUtil.copyToList(buttonList, MenuFieldPowerTreeVO.class);
            for (MenuFieldPowerTreeVO buttonTreeVO:buttonListVOS){
                buttonTreeVO.setTreeType(MenuOrFieldPowerTreeEnum.MENU);
                buttonTreeVO.setIsSelected(roleMenuMap.containsKey(Long.valueOf(buttonTreeVO.getId())) ? YesOrNoEnum.YES : YesOrNoEnum.NO);
            }
            return buttonListVOS;
        }
        return null;
    }
//
//
    /**
     * 组装二级菜单的字段权限信息
     *
     * @param fieldPowerId 字段权限编码
     * @param longListMap          字段权限信息
     * @param roleFieldPowerMap    选中的字段权限
     * @return
     */
    public List<MenuFieldPowerTreeVO> infoFieldPower(Long fieldPowerId, Map<Long, List<SysFieldPower>> longListMap, Map<Long, Long> roleFieldPowerMap) {
        //组装字段权根目录
        List<MenuFieldPowerTreeVO> list = new ArrayList<>();
        MenuFieldPowerTreeVO vo = new MenuFieldPowerTreeVO();
        vo.setId( IdUtil.simpleUUID());
        vo.setTitle("隐藏字段");
        vo.setTreeType(MenuOrFieldPowerTreeEnum.SIGN);
        if(fieldPowerId!=null&&longListMap!=null&&longListMap.size()>0){
            //获取字段权限
            List<SysFieldPower> fieldPowerList = longListMap.get(fieldPowerId);
            List<MenuFieldPowerTreeVO> childList = BeanUtil.copyToList(fieldPowerList, MenuFieldPowerTreeVO.class);
            for (MenuFieldPowerTreeVO fieldPowerTreeVO : childList) {
                fieldPowerTreeVO.setIsSelected(roleFieldPowerMap.containsKey(Long.valueOf(fieldPowerTreeVO.getId())) ? YesOrNoEnum.YES : YesOrNoEnum.NO);

                if(vo.getIsSelected()==null&&fieldPowerTreeVO.getIsSelected()== YesOrNoEnum.YES ){
                    vo.setIsSelected(YesOrNoEnum.YES );
                }
                fieldPowerTreeVO.setTreeType(MenuOrFieldPowerTreeEnum.FIELD_POWER);
            }
            vo.setChildMenuFieldPowerTrees(childList);
        }

        list.add(vo);
        return list;
    }


}

